package com.zhan.drugStore.config;

import com.auth0.jwt.JWT;
import com.zhan.drugStore.bean.bo.UserBO;
import com.zhan.drugStore.constant.RedisConstant;
import com.zhan.drugStore.enums.ResultEnum;
import com.zhan.drugStore.exception.BusinessException;
import com.zhan.drugStore.dao.SysRoleMapper;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Optional;
import java.util.Set;

/**
 * 版权：点钢科技有限公司上海分公司
 * 功能：Realm授权与验证
 * 作者：詹银
 * 邮箱：zhanyin@esteel.com
 * 日期：2021/4/23
 */
public class JwtRealm extends AuthorizingRealm {

    @Resource
    private RedissonClient redissonClient;
    @Resource
    private SysRoleMapper roleMapper;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    /**
     * 授权，将当前用户的角色和权限加入到shiro组件中
     * controller方法用@RequirePermission,不建议使用@RequireRole。
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        UserBO user = (UserBO) SecurityUtils.getSubject().getPrincipal();
        SimpleAuthorizationInfo auth = new SimpleAuthorizationInfo();
        Set<String> roleCodeSet = roleMapper.getRoleCodeByUserId(user.getId());
        Set<String> permissionCodeSet = roleMapper.getPermissionCodeByUserId(user.getId());
        if (!CollectionUtils.isEmpty(user.getRoleSet())) auth.setRoles(roleCodeSet);
        if (!CollectionUtils.isEmpty(user.getPermissionSet())) auth.setStringPermissions(permissionCodeSet);
        return auth;
    }

    /**
     * 认证
     *
     * @param auth
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) {
        String token = (String) auth.getPrincipal();
        String username = JWT.decode(token).getClaim("username").asString();
        RBucket<Object> bucket = redissonClient.getBucket(RedisConstant.USER + username);
        UserBO userBO = (UserBO) bucket.get();
        Optional.ofNullable(userBO).orElseThrow(() -> new BusinessException(ResultEnum.ERR_TOKEN));
        return new SimpleAuthenticationInfo(userBO, token, username);
    }

}
